package com.egor.views.components.modalboxes;

import com.egor.data.entity.Order;
import com.egor.data.enums.OrderStatus;
import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.BeanValidationBinder;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.binder.ValidationException;
import com.vaadin.flow.shared.Registration;
import com.vaadin.flow.spring.annotation.RouteScope;
import lombok.Getter;
import org.springframework.stereotype.Component;

@RouteScope
@Component
public class EditOrderModalBox extends Dialog {
    private Order order;
    private final VerticalLayout layout = new VerticalLayout();
    private final TextField name = new TextField("Order name");
    private final TextField address = new TextField("Order address");
    private final ComboBox<OrderStatus> orderStatus = new ComboBox<>("Order status");
    private final Binder<Order> binder = new BeanValidationBinder<>(Order.class);
    private final Button save = new Button("Save");
    private final Button cancel = new Button("Cancel");

    public EditOrderModalBox() {
        setClassName("order-edit");
        setHeaderTitle("Edit/create order");

        binder.bindInstanceFields(this);

        setFields();
        setButtons();
    }

    public void setOrder(Order order) {
        this.order = order;
        binder.setBean(this.order);
    }

    private void setFields() {
        name.setClearButtonVisible(true);
        address.setClearButtonVisible(true);

        orderStatus.setItems(OrderStatus.values());
        orderStatus.setItemLabelGenerator(OrderStatus::getStatusName);

        layout.add(name, address, orderStatus);
        add(layout);
    }

    private void setButtons() {
        save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        save.addClickShortcut(Key.ENTER);
        cancel.addClickShortcut(Key.ESCAPE);

        save.addClickListener(event -> validateAndSave());
        cancel.addClickListener(event -> fireEvent(new CloseEvent(this)));

        binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));

        getFooter().add(cancel, save);
    }

    private void validateAndSave() {
        try {
            binder.writeBean(order);
            fireEvent(new SaveEvent(this, order));
        } catch (ValidationException e) {
            throw new RuntimeException(e);
        }
    }

    @Getter
    public static abstract class EditOrderEvent
            extends ComponentEvent<EditOrderModalBox> {
        private final Order order;

        public EditOrderEvent(EditOrderModalBox source, Order order) {
            super(source, false);
            this.order = order;
        }
    }

    public static class SaveEvent extends EditOrderEvent {
        public SaveEvent(EditOrderModalBox source, Order order) {
            super(source, order);
        }
    }

    public static class CloseEvent extends EditOrderEvent {
        public CloseEvent(EditOrderModalBox source) {
            super(source, null);
        }
    }

    public <T extends ComponentEvent<?>> Registration addListener(Class<T> eventType,
                                                                  ComponentEventListener<T> listener) {
        return getEventBus().addListener(eventType, listener);
    }
}
